package com.ruiyi.adrobot.mongo.robot.impl;

import com.mongodb.DBObject;
import com.ruiyi.adrobot.beans.Group;
import com.ruiyi.adrobot.beans.Robot;
import com.ruiyi.adrobot.beans.common.MongoPageRequest;
import com.ruiyi.adrobot.beans.socket.Heart;
import com.ruiyi.adrobot.mongo.fun.FunRepository;
import com.ruiyi.adrobot.mongo.robot.RobotOperations;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;

/**
 * Created by Lenovo on 2017/5/9.
 */
public class RobotRepositoryImpl implements RobotOperations {
    @Autowired
    private MongoOperations mongo;
    @Autowired
    private FunRepository funRepository;

    @Override
    public void updateOnlineAndBusyFalse() {
        Query query = new Query(Criteria.where("online").is(true));
        Update update = new Update();
        update.set("online", false);
        update.set("busy", false);
        mongo.updateMulti(query, update, Robot.class);
    }

    @Override
    public Long countByGroupNameAndNickName(String groupName, String nickName) {
        Query query = new Query(Criteria.where("groupName").is(groupName).and("nickName").is(nickName));
        return mongo.count(query, Robot.class);
    }

    @Override
    public void updateBySimCode(String simCode, Update update) {
        Query query = new Query(Criteria.where("simCode").is(simCode));
        mongo.updateFirst(query, update, Robot.class);
    }

    @Override
    public Page<Robot> getListByPage(MongoPageRequest<Robot> mongoPageRequest) {
        Robot params = mongoPageRequest.getParams();
        Query query = new Query();
        if (null != params.getOnline()) {
            query.addCriteria(Criteria.where("online").is(params.getOnline()));
        }
        List<Sort.Order> orders = new ArrayList<Sort.Order>();
        orders.add(new Sort.Order(Sort.Direction.DESC, "busy"));
        Sort sort = new Sort(orders);
        mongoPageRequest.setSort(sort);
        Long count = mongo.count(query, Robot.class);
        List<Robot> taskDetails = mongo.find(query.with(mongoPageRequest), Robot.class);

        return new PageImpl<Robot>(taskDetails, mongoPageRequest, count);
    }

    @Override
    public List<Robot> getCanExcuteRobotsByOnlineAndBusyAndGroupNameAndLockTimeLessThan(List<String> groupNames) {
        Query query = new Query(Criteria.where("busy").is(false).and("lockTime").lt(new Date().getTime()).and("online").is(true));
        if (!groupNames.contains("0")) {
            query.addCriteria(Criteria.where("groupName").in(groupNames));
        }
        return mongo.find(query, Robot.class);
    }

    @Override
    public List<Group> findGroups(Boolean online) {
        List<AggregationOperation> aggregationOperations = new LinkedList<>();
        if (online) {
            aggregationOperations.add(Aggregation.match(Criteria.where("online").is(true)));
        }
        aggregationOperations.add(Aggregation.group("groupName"));
        AggregationResults<Group> outputType = mongo.aggregate(newAggregation(aggregationOperations), "robot", Group.class);
        return outputType.getMappedResults();
    }

    @Override
    public void updateRobotStatus(Heart heart) {
        Query query = new Query(Criteria.where("simCode").is(heart.getSimCode()));
        Update update = new Update();
        update.set("busy", heart.getBusy());
        update.set("online", true);
        if (heart.getBusy() && StringUtils.hasText(heart.getTaskDetailId())) {
            DBObject taskDetail = getTaskByTaskDetailIdAndTaskNum(heart.getTaskDetailId(), heart.getNum());
            DBObject fun = funRepository.findFlowByFunAndFlowId(Integer.valueOf(taskDetail.get("fun").toString()), taskDetail.get("flowId").toString());
            update.set("taskRemark", fun.get("funName").toString() + " " + fun.get("flowName") + " " + heart.getProgress());
        } else {
            update.set("taskRemark", "");
        }
        mongo.updateFirst(query, update, Robot.class);
    }

    @Override
    public DBObject getTaskByTaskDetailIdAndTaskNum(String id, Integer num) {
        Aggregation agg = newAggregation(
                Aggregation.match(Criteria.where("_id").is(new ObjectId(id))),
                Aggregation.unwind("tasks"),
                Aggregation.match(Criteria.where("tasks.num").is(num)),
                Aggregation.project("_id", "fun", "tasks.flowId")
        );
        AggregationResults<DBObject> outputType = mongo.aggregate(agg, "taskDetail", DBObject.class);
        return outputType.getUniqueMappedResult();
    }

}
